package com.jiao.table.entity;

import com.jiao.comm.exception.CacheSysException;
import com.jiao.comm.exception.ReaderCacheInfoException;
import com.jiao.table.annotation.PrimaryKey;
import com.jiao.table.annotation.TableCache;
import com.jiao.table.annotation.TableIndex;
import com.jiao.table.config.CacheKeyDefinition;
import lombok.Getter;
import org.springframework.util.CollectionUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: vincent.jiao
 * @Date: 2021/4/24
 */
public class TableInfo {
    @Getter
    private String tableName;
    @Getter
    private String tableNameKey;

    @Getter
    private String mateDataMaxIdNumKey;

    @Getter
    private String mateDataVersionKey;

    @Getter
    private Class mapperClass;

    @Getter
    private Class entityClass;

//    @Getter
//    private Method selectAllMethod;
//
//    @Getter
//    private Method selectByPrimaryKeyMethod;
//
//    @Getter
//    private Method deleteByPrimaryKeyMethod;

    @Getter
    private Field primaryKeyField;

    @Getter
    private String seqName;

    @Getter
    private boolean isManualGeneration;

    @Getter
    private String dataStatusKey;

    private List<Field> indexFieldList;

    /** 索引字段名， key全路径 */
    private Map<String, String> indexKeyMap = null;

    public TableInfo(Class entityClass) throws NoSuchMethodException {
        this.entityClass = entityClass;
        init();
    }

    private void init() throws NoSuchMethodException {
        // 解析出表名
        Annotation annotationObj = entityClass.getAnnotation(TableCache.class);
        if(annotationObj == null){
            throw new CacheSysException("此类未使用 @TableCache 注解修饰, 请使用此注解支持对应表的缓存");
        }

        TableCache tableCacheAnno = (TableCache) annotationObj;
        String tablename = tableCacheAnno.tableName();
        setTableName(tablename);
        this.mateDataMaxIdNumKey = CacheKeyDefinition.getMateDataMaxIdNumKey(tablename) ;
        this.mateDataVersionKey = CacheKeyDefinition.getMateVersionTime(tablename);

        // 解析出索引
        parseIndex();

        this.dataStatusKey = CacheKeyDefinition.getDataStatus(tablename);
    }

    /**
     * 获取元数据中某个索引的全部值.
     * @param index
     * @return
     */
    public String getMateDataIndexAllValueKey(String index){
        return CacheKeyDefinition.getMateDataIndexAllValueKey(tableName, index);
    }

    private void parseIndex(){
        Field[] allField = entityClass.getDeclaredFields();
        Annotation annotationObj = null;
        this.indexFieldList = new ArrayList<>(16);
        this.indexKeyMap = new HashMap<>(16);

        for (Field field : allField){
            annotationObj = field.getAnnotation(PrimaryKey.class);
            field.setAccessible(true);

            if(annotationObj != null){
                this.primaryKeyField = field;
                PrimaryKey tableId = (PrimaryKey) annotationObj;
                this.seqName = tableId.seqName();
                this.isManualGeneration = tableId.isManualGeneration();
            }


            annotationObj = field.getAnnotation(TableIndex.class);
            if(annotationObj != null){
                this.indexFieldList.add(field);
                this.indexKeyMap.put(field.getName(), CacheKeyDefinition.getIndexKey(tableName, field.getName()));
            }
        }
    }

    private void setTableName(String tableName){
        this.tableName = tableName;
        this.tableNameKey = CacheKeyDefinition.getTableDataKey(tableName);
    }

    public void setIndexFieldList(List<Field> indexFieldList){
        this.indexFieldList = indexFieldList;
        if (!CollectionUtils.isEmpty(indexFieldList)){
            indexKeyMap = new HashMap<>();

            indexFieldList.stream().forEach((item) -> {
                indexKeyMap.put(item.getName(), CacheKeyDefinition.getIndexKey(tableName, item.getName()));
            });
        }
    }

    public String getIndexKey(String indexKey){
        return indexKeyMap.get(indexKey);
    }

    public String getIndexValueKey(String indexKey, String value){
        return CacheKeyDefinition.getIndexValueKey(indexKeyMap.get(indexKey), value) ;
    }

    public String getIndexKey(Field field){
        return indexKeyMap.get(field.getName());
    }

    public String getMateDataBitMapKey(){
        return CacheKeyDefinition.getMateDataBitMap(tableName);
    }

    public Collection<String> getAllIndexFieldName(){
        return indexKeyMap.keySet();
    }

    /**
     * 返回实体对应的索引信息.
     * @param obj
     * @return Map<全路径 + 索引值, id值>
     * @throws IllegalAccessException
     */
    public Map<String, Object> getAllIndexKVMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<>();
        Object primaryKey = primaryKeyField.get(obj);

        for (Field item : indexFieldList){
            item.setAccessible(true);
            map.put(CacheKeyDefinition.getIndexKey(tableName, item.getName()) + ":" + item.get(obj), primaryKey);
        }

        return map;
    }

    /**
     * 返回实体对应的元数据索引信息.
     * @param obj
     * @return Map<全路径 + 索引值, id值>
     * @throws IllegalAccessException
     */
    public Map<String, Object> getMateDataAllIndexKVMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<>();

        for (Field item : indexFieldList){
            item.setAccessible(true);
            map.put(CacheKeyDefinition.getMateDataIndexAllValueKey(tableName, item.getName()), item.get(obj));
        }

        return map;
    }

    public String getPrimaryKeyName() {
        return primaryKeyField.getName();
    }
}
